package com.mp.approvalreq.util;

import com.mp.approvalreq.entity.Flow;
import com.mp.approvalreq.entity.Request;
import com.mp.user.entity.User;
import com.plusmoney.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class FlowUtils {

    private static final Logger logger = LoggerFactory.getLogger(FlowUtils.class);

    public static TreeMap<Integer, List<Flow>> groupByOrdering(List<Flow> flows) {
        TreeMap<Integer, List<Flow>> map = new TreeMap<>();
        for (Flow flow : flows) {
            if (!map.containsKey(flow.getOrdering())) {
                map.put(flow.getOrdering(), new ArrayList<>());
            }
            map.get(flow.getOrdering()).add(flow);
        }
        return map;
    }

    /**
     * 获取当前进行中的审批流
     *
     * @param flows
     * @return
     */
    public static List<Flow> getCurrentFlows(List<Flow> flows) {
        return flows.stream().filter(flow -> flow.getIsApproved() == Flow.APPROVING).collect(Collectors.toList());
    }

    /**
     * 获取当前层级的审批流
     *
     * @param flows
     * @param ordering
     * @return
     */
    public static List<Flow> getFlowsByOrdering(List<Flow> flows, int ordering) {
        return flows.stream().filter(flow -> flow.getOrdering() == ordering).collect(Collectors.toList());
    }

    /**
     * 获取当前层级之后的审批流
     *
     * @param flows
     * @param ordering
     * @return
     */
    public static List<Flow> getFollowFlows(List<Flow> flows, int ordering) {
        return flows.stream().filter(flow -> flow.getOrdering() > ordering).collect(Collectors.toList());
    }

    public static List<Flow> getDefaultFlows(List<Flow> flows) {
        return flows.stream().filter(flow -> flow.getFlowType() == Flow.FLOW_TYPE_DEFAULT).collect(Collectors.toList());
    }

    public static List<Flow> getFinancialFlows(List<Flow> flows) {
        return flows.stream().filter(flow -> flow.getFlowType() == Flow.FLOW_TYPE_FINANCIAL).collect(Collectors.toList());
    }

    public static Flow getLastConfirmByCompanyInfoId(List<Flow> flows, Integer companyInfoId) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        for (int i = flows.size() - 1; i >= 0; i--) {
            Flow flow = flows.get(i);
            if (Objects.equals(flow.getCompanyInfoId(), companyInfoId) && Utils.isNotNull(flow.getIsApprovedAt())) {
                return flow;
            }
        }
        return null;
    }

    public static boolean isExistContactFlow(List<Flow> flows, Integer contactId) {
        return flows.stream().anyMatch(flow -> Objects.equals(flow.getContactId(), contactId));
    }

    public static boolean isExistUserFlow(List<Flow> flows, Integer companyInfoId) {
        return Utils.isNotNull(getFlowsByCompanyInfoId(flows, companyInfoId));
    }

    public static boolean isExistUserFlow(List<Flow> flows, User user) {
        if (Utils.isNull(user)) {
            return false;
        }
        return Utils.isNotNull(getFlowsByCompanyInfoId(flows, user.getCompanyInfoId()));
    }

    public static Flow getFlowsByCompanyInfoId(List<Flow> flows, Integer companyInfoId) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        return flows.stream().filter(flow -> Objects.equals(flow.getCompanyInfoId(), companyInfoId)).findFirst().orElse(null);
    }

    public static Flow getNotApprovedFlowByCompanyInfoId(List<Flow> flows, Integer companyInfoId) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        return flows.stream().filter(flow -> Objects.equals(flow.getCompanyInfoId(), companyInfoId) && StringUtils.isBlank(flow.getIsApprovedAt())).findFirst().orElse(null);
    }

    public static String getContactIds(List<Flow> flows) {
        List<Integer> ids = new ArrayList<>();
        for (Flow flow : flows) {
            ids.add(flow.getContactId());
        }
        return ListHelper.list2string(ids);
    }

    public static String getCompanyInfoIds(List<Flow> flows) {
        List<Integer> ids = flows.stream().map(Flow::getCompanyInfoId).collect(Collectors.toList());
        return ListHelper.list2string(ids);
    }

    public static String getApproveTimes(List<Flow> flows) {
        StringBuilder sb = new StringBuilder();
        for (Flow flow : flows) {
            if (StringUtils.isNotEmpty(flow.getIsApprovedAt())) {
                sb.append(flow.getIsApprovedAt());
                sb.append(",");
            }
        }
        if (StringUtils.isNotEmpty(sb)) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return StringUtils.isBlank(sb) ? null : sb.toString();
    }

    /**
     * 获取拒绝id列表（contactId,最多一个）
     *
     * @param flows
     * @return
     */
    public static String getRefuseContactIds(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        return flows.stream().filter(Flow::hasRefuse).findFirst().map(flow -> String.valueOf(flow.getContactId())).orElse(null);
    }

    /**
     * 获取拒绝id列表（companyInfoId,最多一个）
     *
     * @param flows
     * @return
     */
    public static String getRefuseCompanyInfoIds(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        return flows.stream().filter(Flow::hasRefuse).findFirst().map(flow -> String.valueOf(flow.getCompanyInfoId())).orElse(null);
    }

    /**
     * 获取批准id列表（contactId）
     *
     * @param flows
     * @return
     */
    public static String getConfirmContactIds(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        List<Integer> list = flows.stream().filter(Flow::hasConfirmed).map(Flow::getContactId).collect(Collectors.toList());
        return Utils.isEmpty(list) ? null : ListHelper.list2string(list);
    }

    /**
     * 获取批准id列表（companyInfoId）
     *
     * @param flows
     * @return
     */
    public static String getConfirmCompanyInfoIds(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return null;
        }
        int ordering = 0;
        String orTime = null;
        List<Integer> list = new ArrayList<>();
        for (Flow flow : flows) {
            if (flow.hasConfirmed()) {
                list.add(flow.getCompanyInfoId());
                if (flow.getType() == Flow.MODE_OR) {
                    ordering = flow.getOrdering();
                    orTime = flow.getIsApprovedAt();
                }
            } else {
                if (flow.getType() == Flow.MODE_OR && flow.getOrdering() == ordering && StringUtils.isNotBlank(orTime)) {
                    list.add(flow.getCompanyInfoId());
                }
            }
        }
        return Utils.isEmpty(list) ? null : ListHelper.list2string(list);
    }

    /**
     * 当前层是否已批准（或签:有一个批准即可;其他:全部批准）
     *
     * @param flows
     * @return
     */
    public static boolean isConfirmByOrdering(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return false;
        }
        int type = flows.get(0).getType();
        switch (type) {
            case Flow.MODE_DEFAULT:
            case Flow.MODE_AND:
                return isAllConfirm(flows);
            case Flow.MODE_OR:
                return existConfirm(flows);
            default:
                return false;
        }
    }

    public static boolean isRefuseByOrdering(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return false;
        }
        int type = flows.get(0).getType();
        switch (type) {
            case Flow.MODE_DEFAULT:
            case Flow.MODE_OR:
                return isAllRefuse(flows);
            case Flow.MODE_AND:
                return existRefuse(flows);
            default:
                return false;

        }
    }

    public static boolean isFinalRefuse(List<Flow> flows) {
        for (Flow flow : flows) {
            if (flow.hasRefuse()) {
                if (flow.getType() == Flow.MODE_DEFAULT || flow.getType() == Flow.MODE_AND) {
                    logger.info("mode:{},存在驳回", flow.getType());
                    return true;
                }
                List<Flow> flowsByOrdering = getFlowsByOrdering(flows, flow.getOrdering());
                for (Flow f : flowsByOrdering) {
                    if (!f.hasRefuse()) {
                        return false;
                    }
                }
                logger.info("mode:{},全部驳回", flow.getType());
                return true;
            }
        }
        return false;
    }

    /**
     * 是否全部批准（判断最后一层是否已批准）
     *
     * @param flows
     * @return
     */
    public static boolean isFinalConfirm(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            EmailUtils.sendMail("审批流为空", null);
            return true;
        }
        int maxOrdering = getMaxOrdering(flows);
        return isConfirmByOrdering(getFlowsByOrdering(flows, maxOrdering));
    }

    /**
     * 获取最后一层审批
     *
     * @param flows
     * @return
     */
    public static List<Flow> getLastFlows(List<Flow> flows) {
        return getFlowsByOrdering(flows, getMaxOrdering(flows));
    }

    /**
     * 获取最大的审批层级（最后一层）
     *
     * @param flows
     * @return
     */
    public static int getMaxOrdering(List<Flow> flows) {
        int max = 1;
        for (Flow flow : flows) {
            max = Math.max(flow.getOrdering(), max);
        }
        return max;
    }

    /**
     * 审批流是否全部批准
     *
     * @param flows
     * @return
     */
    private static boolean isAllConfirm(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return false;
        }
        return flows.stream().allMatch(Flow::hasConfirmed);
    }

    /**
     * 审批流是否全部驳回
     *
     * @param flows
     * @return
     */
    private static boolean isAllRefuse(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return false;
        }
        return flows.stream().allMatch(Flow::hasRefuse);
    }

    /**
     * 审批流是否存在批准
     *
     * @param flows
     * @return
     */
    public static boolean existConfirmOrRefuse(List<Flow> flows) {
        return flows.stream().anyMatch(flow -> flow.getIsApproved() == Flow.CONFIRM || flow.getIsApproved() == Flow.REFUSED);
    }

    /**
     * 审批流是否存在批准
     *
     * @param flows
     * @return
     */
    public static boolean existConfirm(List<Flow> flows) {
        return flows.stream().anyMatch(flow -> flow.getIsApproved() == Flow.CONFIRM);
    }

    public static boolean existRefuse(List<Flow> flows) {
        return flows.stream().anyMatch(flow -> flow.getIsApproved() == Flow.REFUSED);
    }

    /**
     * 转化审批人信息
     *
     * @param request
     * @param user
     * @param flows
     */
    public static void transferRequestInfo(Request request, User user, List<Flow> flows) {
        request.setAllJudger(getContactIds(flows));
        request.setAllJudgerCiid(getCompanyInfoIds(flows));

        request.setWhoRefused(getRefuseContactIds(flows));
        request.setWhoRefusedCiid(getRefuseCompanyInfoIds(flows));

        request.setWhoConfirm(getConfirmContactIds(flows));
        request.setWhoConfirmCiid(getConfirmCompanyInfoIds(flows));

        request.setCheckedTime(getApproveTimes(flows));
        request.setRequestStep(getRequestStep(flows));

        List<Flow> financialFlows = FlowUtils.getFinancialFlows(flows);
        if (Utils.isNotEmpty(financialFlows)) {
            Flow last = Utils.getLast(financialFlows);
            if (last.hasConfirmed()) {
                logger.info("最后一级财务审批人已批准");
                request.setFinancialStatus(2);
            } else {
                List<Flow> beforeFlows = FlowUtils.getFlowsByOrdering(flows, last.getOrdering());
                Flow before = Utils.getFirst(beforeFlows);
                if (Utils.isNotNull(before)) {
                   if (before.hasConfirmed()){
                       request.setFinancialStatus(1);
                   }else {
                       request.setFinancialStatus(0);
                   }
                }
            }

        }

        List<Flow> currentFlows = getCurrentFlows(flows);
        if (Utils.isEmpty(currentFlows)) {
            return;
        }
        if (FlowUtils.isExistUserFlow(currentFlows, user)) {
            request.setWhoTheNext(String.valueOf(user.getContactId()));
            request.setWhoTheNextCiid(String.valueOf(user.getCompanyInfoId()));
            return;
        }
        Flow flow = currentFlows.get(0);
        request.setWhoTheNext(String.valueOf(flow.getContactId()));
        request.setWhoTheNextCiid(String.valueOf(flow.getCompanyInfoId()));
    }

    private static Integer getRequestStep(List<Flow> flows) {
        return (int) flows.stream().filter(flow -> StringUtils.isNotBlank(flow.getIsApprovedAt())).count();
    }

    /**
     * 是否被其他审批人批准过的（或签）
     *
     * @param flows
     * @return
     */
    public static boolean existOtherConfirm(List<Flow> flows) {
        if (Utils.isEmpty(flows)) {
            return false;
        }
        if (flows.get(0).getType() != Flow.MODE_OR) {
            return false;
        }
        return existConfirm(flows);
    }

    public static void resetFlows(List<Flow> newFlows) {
        if (Utils.isEmpty(newFlows) || isFinalConfirm(newFlows)) {
            return;
        }
        newFlows.sort(Comparator.comparingInt(Flow::getOrdering));

        int ordering = newFlows.stream().filter(flow -> flow.getIsApproved() == 0).findFirst().map(Flow::getOrdering).orElse(0);
        if (ordering == 0) {
            return;
        }
        newFlows.stream().filter(flow -> flow.getOrdering() > ordering).forEach(flow -> flow.setIsApproved(Flow.NOT_YET));
    }
}
